/*
 * Copyright 2002-2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.tigris.jasmincc.framework.namespace.implementation;

import java.io.*;
import java.util.*;

import org.tigris.jasmincc.framework.namespace.Namespace;
import org.tigris.jasmincc.framework.namespace.NamespaceManager;

/**
 * A namespace manager realization.
 * 
 * @author Sam Huang
 * 
 */
public class SimpleNamespaceManager implements NamespaceManager {

	protected Map<String, String> grammarBases = null;

	protected List<Namespace> namespaces = null;

	protected FilenameFilter filenameFilter = null;

	protected String defaultGrammarBase;

	/**
	 * Constructor with default grammar base specified.
	 * 
	 * @param defaultGrammarBase
	 * @throws FileNotFoundException
	 */
	public SimpleNamespaceManager(String defaultGrammarBase)
			throws FileNotFoundException {
		isFileExisted(defaultGrammarBase);

		namespaces = new ArrayList<Namespace>();
		grammarBases = new HashMap<String, String>();

		this.defaultGrammarBase = defaultGrammarBase;
	}

	/**
	 * Set the default grammar base.
	 * 
	 * @param grammarBases
	 *            the grammarBases to set
	 */
	public void setGrammarBases(Map<String, String> grammarBases)
			throws FileNotFoundException {
		for (String str : grammarBases.values()) {
			isFileExisted(str);
		}
		this.grammarBases = grammarBases;
	}

	/**
	 * Set the file name filter for the grammars.
	 * 
	 * @param filenameFilter
	 */
	public void setFilenameFilter(FilenameFilter filenameFilter) {
		this.filenameFilter = filenameFilter;
	}

	/**
	 * Add a new grammar base.
	 * 
	 * @param namespaceName the namespace's name
	 * @param physicalLocation the full path in file system
	 */
	public void addGrammarBase(String namespaceName, String physicalLocation)
			throws FileNotFoundException {
		isFileExisted(physicalLocation);
		grammarBases.put(namespaceName, physicalLocation);
	}

	/**
	 * @param physicalLocation
	 * @throws FileNotFoundException
	 */
	private static void isFileExisted(String physicalLocation)
			throws FileNotFoundException {
		File dir = new File(physicalLocation + File.separatorChar);
		if (!(dir.exists() && dir.isDirectory())) {
			throw new FileNotFoundException(physicalLocation);
		}
	}

	/**
	 * 
	 */
	public Namespace addNamespace(String namespaceName) throws Exception {
		String grammarBase;

		if (grammarBases.containsKey(namespaceName)) {
			grammarBase = grammarBases.get(namespaceName);
		} else {
			grammarBase = defaultGrammarBase;
		}
		Namespace namespace = new Namespace(namespaceName, grammarBase);
		namespaces.add(namespace);
		return namespace;
	}

	/**
	 * 
	 * @param name
	 */
	public boolean isAnInterface(String name) {
		// TODO change it with a more specific implementation
		return name.startsWith("!");
	}

	/**
	 * Get file by using the specified grammar name.
	 * 
	 * 	@param name
	 */
	public File getFileByGrammarName(String name) throws Exception {
		File file = null;
		int dot = name.lastIndexOf('.');
		if (dot > 0) {
			// if the grammar name is in qualified form
			String namespaceName = name.substring(0, dot);
			String entityName = name.substring(dot + 1);

			// look for the grammar from the namespace
			for (Namespace namespace : namespaces) {
				if (namespace.getName().equals(namespaceName)) {
					file = namespace.getEntity(entityName);
					if (file != null) {
						return file;
					}
				}
			}
			// is the namespace not yet added to the pool?
			// include it and retrieve it agian
			Namespace namespace = addNamespace(namespaceName);
			return namespace.getEntity(entityName);
		}
		// return the first grammar found
		for (final Namespace namespace : namespaces) {
			file = namespace.getEntity(name);
			if (file != null) {
				return file;
			}

		}

		// cannot find the grammar
		return null;
	}

	public Namespace getNamespace(String name) {
		for (Namespace namespace : namespaces) {
			if (namespace.getName().equals(name)) {
				return namespace;
			}
		}

		return null;
	}

	/**
	 * Change the default grammar base.
	 * 
	 * @param defaultGrammarBase the grammar base to be changed
	 * 
	 */
	public void setDefaultGrammarBase(String defaultGrammarBase) {
		this.defaultGrammarBase = defaultGrammarBase;
	}

}
